/*
 * Created on Jun 23, 2004
 */
package org.vectrics.recruiter.user;

import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import org.vectrics.SystemException;
import org.vectrics.batch.Batch;
import org.vectrics.common.html.Cell;
import org.vectrics.common.html.Row;
import org.vectrics.common.html.Table;
import org.vectrics.common.util.DateSync;
import org.vectrics.domain.Domain;
import org.vectrics.hibernate.ThreadProperties;
import org.vectrics.location.Locale;
import org.vectrics.mail.MailException;
import org.vectrics.mail.MailMessage;
import org.vectrics.mail.NotificationProvider;
import org.vectrics.provider.CoreServiceLocator;
import org.vectrics.recruiter.RecruitServiceLocator;
import org.vectrics.recruiter.config.RecruitConfig;
import org.vectrics.recruiter.job.Job;
import org.vectrics.user.ContactInfo;
import org.vectrics.user.Person;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author mmoore
 */
public class JobAgentsBatch extends Batch {
	private transient final Log log = LogFactory.getLog(this.getClass());
	private int MAX_FAILURE_COUNT = 3;
	private String background = "#eeeeff";
	private String BATCH_TYPE_CODE = "job.agent.run";
	private String BATCH_DESCRIPTION = "Job Agent Run";
	private static boolean working = false;
	
	protected String getBatchTypeCode() {
		return(BATCH_TYPE_CODE);
	}
	/**
	 * 
	 */
	public JobAgentsBatch(Domain domain) {
		super(domain);
	}

	protected boolean persistRunResults() {
		return(true);
	}
	
	
	public String getDescription() {
		return(BATCH_DESCRIPTION);
	}
	
	protected boolean logOnlyErrors() {
		return(false);
	}

	protected boolean executeForEachDomain() {
		return(true);
	}
	
	
	/*
	 * 
	 */
	protected void execute(Domain domain) {
	    processJobAgents(domain);
	}
	
	public boolean hasOtherRunningInstance() {
		return(working);
	}
	
	private void processJobAgents(Domain domain) {
		try {
			log.debug("processJobAgents() called " +
					"\r\n - Data owner: " + domain);
			working = true;
		    log.debug("Starting InvokeJobAgents");

			log.debug("Job Agent execution will happen in background, make thread low priority.");
			if (Thread.currentThread() != null)
				Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
	
			Date now = new Date();
			boolean done = false;
			while (!done) {
				ThreadProperties.getSession().clear();
				Collection jobAgentList = RecruitServiceLocator.getRecruitUserService().findExpiredJobAgents(domain, now, 100);
				
				
				if (jobAgentList.size() > 0 ) {
					log.info("Running job agents, agent count = " + jobAgentList.size() + "  Data owner: " + domain);
					Iterator iter = jobAgentList.iterator();
					while (iter.hasNext()) {
						JobAgent jobAgent = (JobAgent)iter.next();
						Integer failureCount = jobAgent.getSendFailureCount();
						try {
						    runJobAgent(domain, jobAgent);
							
							Calendar calendar = Calendar.getInstance();
							calendar.setTime(DateSync.getCurrentTime());
							calendar.add(Calendar.DATE, 1);
				            jobAgent.setDateLastServiced(DateSync.getCurrentTime());
							jobAgent.setTriggerDate(calendar.getTime());
							if (log.isDebugEnabled())
								log.info("Job Agent, new trigger date = " + calendar.getTime());
							RecruitServiceLocator.getRecruitUserService().updateJobAgent(jobAgent);
						    ThreadProperties.forcedCommit();
							log.debug("Job Agent update finished");
						} catch (Exception ex) {
							log.error("Exception running job agent", ex);
						    try {
						        if (jobAgent.getSendFailureCount().intValue() >= this.MAX_FAILURE_COUNT) {
						            runJobAgent(domain, jobAgent);
								    jobAgent.setSendFailureCount(new Integer(0));
								    RecruitServiceLocator.getRecruitUserService().updateJobAgent(jobAgent);
								    ThreadProperties.forcedCommit();
						        } else {
						            if (log.isDebugEnabled())
						                log.debug("Did not run agent with error count exceeding maximum: " 
						                        + jobAgent.getName());
						        }
						        
						    } catch (Throwable ex2) {
						        log.error("Exception running job agent: " + jobAgent.getId(), ex2);
							    failureCount = new Integer(failureCount.intValue() + 1);
							    jobAgent.setSendFailureCount(failureCount);
							    RecruitServiceLocator.getRecruitUserService().updateJobAgent(jobAgent);
						    }
						}
					}
				} else {
					done = true;
				}
			}
			ThreadProperties.forcedCommit();
			
		} catch (Exception ex) {
			log.error("Exception running job agents: " + ex.getLocalizedMessage());
			log.info("Rolling back transaction due to exception");
			ThreadProperties.rollbackTransaction();
		    throw new SystemException("Exception running job agents: " + ex.getLocalizedMessage());
		} finally {
			working = false;
		}
	}
	
	
	/*
	 * Find jobs and send e-mail.
	 */
	private void runJobAgent(Domain domain, JobAgent jobAgent) throws MailException {
		Long personId = jobAgent.getCandidateInfo().getPerson().getId();
		Person person = CoreServiceLocator.getPersonService().findPersonById(personId);
		Collection jobList = RecruitServiceLocator.getRecruitUserService().findJobsForJobAgent(jobAgent, 100);
		
		ContactInfo contactInfo = person.getContactInfo();
		if (contactInfo != null) {
			if (contactInfo.getEmail() != null) {
				if (contactInfo.getHtmlEmail().booleanValue()) {
					sendHtmlAgentReport(domain, jobList, person, jobAgent);
				} else {
					sendTextAgentReport(domain, jobList, person, jobAgent);
				}
			}
			if (contactInfo.getEmail2() != null) {
				if (contactInfo.getHtmlEmail2().booleanValue()) {
					sendHtmlAgentReport(domain, jobList, person, jobAgent);
				} else {
					sendTextAgentReport(domain, jobList, person, jobAgent);
				}
			}
		}
	}
				
	private void sendTextAgentReport(Domain domain, Collection jobList, Person person, JobAgent jobAgent) throws MailException {
		sendAgentReport(domain, false, jobList, person, jobAgent);	
	}
	
	private void sendHtmlAgentReport(Domain domain, Collection jobList, Person person, JobAgent jobAgent) throws MailException {
		sendAgentReport(domain, true, jobList, person, jobAgent);	
	}
		
	private void sendAgentReport(Domain domain, boolean html, Collection jobList, Person person, JobAgent jobAgent) throws MailException {	
		if (log.isDebugEnabled()) {
			log.debug("Running job agent");
			log.debug(" - ID:              " + jobAgent.getId());
			log.debug(" - Person:          " + person.getName());
			log.debug(" - Agent name:      " + jobAgent.getName());
			log.debug(" - Search phrase:   " + jobAgent.getSearchPhrase());
			log.debug(" - Job Match Count: " + jobList.size());
		}
			
		int jobCount = jobList.size();
		MailMessage message = new MailMessage(domain);
		if (html)
			message.setContentType(MailMessage.CONTENT_HTML);
		else
			message.setContentType(MailMessage.CONTENT_TEXT);
			
		StringBuffer body = new StringBuffer();
		
		if (html) {
			body.append("<html>");
			body.append("  <body>");
			body.append("		<font style=\"font:normal 0.8em Verdana\">Agent: " + jobAgent.getName() + "</font><br><br>");
			body.append("		<font style=\"font:normal 0.8em Verdana\">Phrase: " + jobAgent.getSearchPhrase() + "</font><br><br>");
			body.append("		<font style=\"font:normal 0.8em Verdana\">This job agent found " + jobCount + " jobs.</font><br><br>");
			Table table = new Table();
	
			Iterator iter = jobList.iterator();
			while (iter.hasNext()) {
				Job job = (Job)iter.next();
				appendJobInfo(person.getLocale(), job, table);
			}
			
			body.append(table.toString());
			
			body.append("  </body>");
			body.append("</html>");
		} else {
			body.append("Agent: " + jobAgent.getName() + "\r\n");
			body.append("Phrase: " + jobAgent.getSearchPhrase() + " jobs.\r\n");
			body.append("This job agent found " + jobCount + " jobs.\r\n\r\n");
			
			Iterator iter = jobList.iterator();
			while (iter.hasNext()) {
				Job job = (Job)iter.next();
				appendTextJobInfo(person.getLocale(), job, body);
			}
			
		}
		
		message.setBody(body.toString());
		message.setSubject("FlashRecruit Job Agent: " + jobAgent.getName());
		message.setFromAddress(RecruitConfig.getRecruitInstance().getMailFromName(domain));
		message.setFromName("FlashRecruit Jobs");
		NotificationProvider.getInstance().sendMessage(person, message);
		
	}

	private void appendTextJobInfo(Locale locale, Job job, StringBuffer body) {
		if (job == null)
			throw new SystemException("Job is null");
		if (ThreadProperties.getDomain() == null)
			throw new SystemException("Thread data owner is null");

		String href = RecruitConfig.getRecruitInstance().getPublicSiteContext() 
				+ "/public/" + ThreadProperties.getUriDomainId() + "/job/job_view.do?jobId=" + job.getId();
		String location = job.getLocationDescription();
		
		body.append("Title:       " + job.getTitle() + "\r\n");
		//body.append("Date Posted: " + DateUtil.getDateFormatRoundToDay(locale.getLocale()).format(job.getDatePosted()) + "\r\n");
		body.append("Location:    " + location + "\r\n");
		body.append("Description: " + job.getDescription() + "\r\n");
		body.append("Link:        " + href + "\r\n");
		body.append("\r\n\r\n");
	}
	
	private void appendJobInfo(Locale locale, Job job, Table table) {
		String href = RecruitConfig.getRecruitInstance().getPublicSiteContext() 
				+ "/public/" + ThreadProperties.getUriDomainId(job.getDomain()) +
						"/job/job_view.do?jobId=" + job.getId();
		String location = job.getLocationDescription();

		Row row;
		Cell cell;
		
		row = table.addRow();
		cell = row.addCell();
		cell.setBgColor(background);
		cell.addElement("<font style=\"font:bold 0.7em Verdana\">" + "Title" + "</font><br><br>");
		cell = row.addCell();
		cell.setBgColor(background);
		cell.addElement("<a href=\"" + href + "\" style=\"font:normal 0.7em Verdana\">" 
				+ job.getTitle() + "</a><br><br>");
		
		row = table.addRow();
		cell = row.addCell();
		cell.setBgColor(background);
		cell.addElement("<font style=\"font:bold 0.7em Verdana\">" + "Date Posted" + "</font><br><br>");
		cell = row.addCell();
		cell.setBgColor(background);
		cell.addElement("<font style=\"font:normal 0.7em Verdana\">" 
						+ CoreServiceLocator.getDateFormat().getDateFormatRoundToDay(locale.getLocale()).format(job.getDatePosted()) + "</font><br><br>");
		
		row = table.addRow();
		cell = row.addCell();
		cell.setBgColor(background);
		cell.addElement("		      <font style=\"font:bold 0.7em Verdana\">" + "Location" + "</font><br><br>");
		cell = row.addCell();
		cell.setBgColor(background);
		cell.addElement("		      <font style=\"font:normal 0.7em Verdana\">" + location + "</font><br><br>");
		
		row = table.addRow();
		cell = row.addCell();
		cell.setBgColor(background);
		cell.addElement("		      <font style=\"font:bold 0.7em Verdana\">" + "Description" + "</font><br><br>");
		cell = row.addCell();
		cell.setBgColor(background);
		cell.addElement("		      <font style=\"font:normal 0.7em Verdana\">" + job.getDescription() + "</font><br><br>");
		
		row = table.addRow();
		cell = row.addCell();
		cell.addElement("&nbsp;<br>");
		cell = row.addCell();
	}
	
}
